import 'dart:math' as math;

import 'package:vector_math/vector_math.dart';
import 'package:vector_math_test/src/test_utils.dart';

import '../common/test_page.dart';

class Matrix2TestPage extends TestPage{
  Matrix2TestPage(super.title) {
    group('Matrix2', () {
      test('Matrix2.determinant', testMatrix2Determinant);
      test('Matrix2.scaleAdjoint', testMatrix2Adjoint);
      test('Matrix2.transformed', testMatrix2Transform);
      test('Matrix2.copyInverse', testMatrix2Inversion);
      test('Matrix2.dotRow和Matrix2.dotColumn', testMatrix2Dot);
      test('Matrix2.scaled', testMatrix2Scale);
      test('Matrix2.solve', testMatrix2Solving);
    });
  }

  void testMatrix2Adjoint() {
    final input = <Matrix2>[];
    final expectedOutput = <Matrix2>[];

    input.add(parseMatrix<Matrix2>('''0.830828627896291   0.549723608291140
                                    0.585264091152724   0.917193663829810'''));
    expectedOutput.add(parseMatrix<Matrix2>(''' 0.917193663829810  -0.549723608291140
                                   -0.585264091152724   0.830828627896291'''));
    input.add(parseMatrix<Matrix2>(''' 1     0
                                     0     1'''));
    expectedOutput.add(parseMatrix<Matrix2>(''' 1     0
                                              0     1'''));

    assert(input.length == expectedOutput.length);

    for (var i = 0; i < input.length; i++) {
      final output = input[i].clone();
      output.scaleAdjoint(1.0);
      relativeTest(output, expectedOutput[i]);
    }
  }

  void testMatrix2Determinant() {
    final input = <Matrix2>[];
    final expectedOutput = <double>[];

    input.add(parseMatrix<Matrix2>('''0.830828627896291   0.549723608291140
                                    0.585264091152724   0.917193663829810'''));
    expectedOutput.add(0.440297265243183);

    assert(input.length == expectedOutput.length);

    for (var i = 0; i < input.length; i++) {
      final output = input[i].determinant();
      relativeTest(output, expectedOutput[i]);
    }
  }

  void testMatrix2Transform() {
    final rot = Matrix2.rotation(math.pi / 4);
    final input = Vector2(0.234245234259, 0.890723489233);

    final expected = Vector2(
        rot.entry(0, 0) * input.x + rot.entry(0, 1) * input.y,
        rot.entry(1, 0) * input.x + rot.entry(1, 1) * input.y);

    final transExpected = Vector2(
        rot.entry(0, 0) * input.x + rot.entry(1, 0) * input.y,
        rot.entry(0, 1) * input.x + rot.entry(1, 1) * input.y);

    relativeTest(rot.transformed(input), expected);
    relativeTest(rot.transposed().transformed(input), transExpected);
  }

  void testMatrix2Inversion() {
    final m = Matrix2(4.0, 3.0, 3.0, 2.0);
    final result = Matrix2.zero();
    final det = result.copyInverse(m);
    expect(det, -1.0);
    expect(result.entry(0, 0), -2.0);
    expect(result.entry(1, 0), 3.0);
    expect(result.entry(0, 1), 3.0);
    expect(result.entry(1, 1), -4.0);
  }

  void testMatrix2Dot() {
    final matrix = Matrix2(1.0, 2.0, 3.0, 4.0);

    final v = Vector2(3.0, 4.0);

    expect(matrix.dotRow(0, v), 15.0);
    expect(matrix.dotRow(1, v), 22.0);
    expect(matrix.dotColumn(0, v), 11.0);
    expect(matrix.dotColumn(1, v), 25.0);
  }

  void testMatrix2Scale() {
    final m = Matrix2(1.0, 2.0, 3.0, 4.0);
    final n = m.scaled(2.0);

    expect(n.storage[0], 2.0);
    expect(n.storage[1], 4.0);
    expect(n.storage[2], 6.0);
    expect(n.storage[3], 8.0);
  }

  void testMatrix2Solving() {
    final A = Matrix2(2.0, 2.0, 8.0, 20.0);
    final AA = Matrix2.fromList([2.0, 2.0, 8.0, 20.0]);
    expect(A, AA);
    final b = Vector2(20.0, 64.0);
    final result = Vector2.zero();

    Matrix2.solve(A, result, b);

    final backwards = A.transform(Vector2.copy(result));

    expect(backwards.x, b.x);
    expect(backwards.y, b.y);
  }

}